#include"c3pom/pluginmanager.h"
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<dirent.h>
#include<dlfcn.h>
#include"c3pom/dynclass.h"
using namespace std;
using namespace c3pom;
static PluginManager* instance=NULL;
PluginMonitor::PluginMonitor()
{
	loc="unknown";
	statu="unknown";
	plugin=NULL;
	threadnum=0;
	omp_init_lock(&lock);
}

PluginManager::PluginManager()
{
	Application::getInstance()->regCommand(new Lspl());
	Application::getInstance()->regCommand(new LoadPlugin());
	Application::getInstance()->regCommand(new RunPlugin());
	log=Log::getInstance();
	omp_init_lock(&pllock);
}
PluginManager* PluginManager::getInstance()
{
	if(instance==NULL)
		instance=new PluginManager();
	return instance;
}
int PluginManager::loadPlugin(string name)
{
	//从插件列表中获取插件
	omp_set_lock(&pllock);
	PluginMonitor* pm=plugins[name];
	omp_unset_lock(&pllock);
	if(pm==NULL)
	{
		log->error(name+" plugin is not exist!");
		return 100;
	}

	//针对找到且有效的插件进行状态调整
	omp_set_lock(&pm->lock);
	if(pm->statu=="loaded"&&pm->plugin!=NULL)
	{
		log->warn(name+"plugin has been loaded");
		omp_unset_lock(&pm->lock);
		return 0;
	}
	if(pm->plugin==NULL)
	{
		//这一段加载并生成plugin实例
		void* handle=dlopen(pm->loc.c_str(),RTLD_LAZY|RTLD_NODELETE);
		void (*regclass)();
		if(handle!=NULL)
		{
			regclass=(void (*)())dlsym(handle,"C3POM_reg_class");//找到插件文件中注册入口类的函数
			if(regclass!=NULL)
			{
				(*regclass)();
				Plugin* p=(Plugin*)DYN_CREATE(name.c_str());
				if(p!=NULL)
				{
					pm->plugin=p;
					pm->statu="loaded";
					log->info("load success");
					omp_unset_lock(&pm->lock);
					p->load();
					return 0;
				}
				log->error("create Plugin faled");
				omp_unset_lock(&pm->lock);
				return 1;
			}
			log->error("regist PLugin failed");
			omp_unset_lock(&pm->lock);
			return 2;
		}
		log->error("open plugin file faled");
		omp_unset_lock(&pm->lock);
		log->error(dlerror());
		return 3;
	}
}

int PluginManager::runPlugin(vector<string> args)
{
	int result=-1;
	if(args.size()<2)
	{
		log->error("need a plugin name");
		return result;
	}
	PluginMonitor* pm=plugins[args[1]];
	if(pm!=NULL)
	{
		omp_set_lock(&pm->lock);
		if(pm->statu=="loaded"||pm->statu=="running")
		{
			if(pm->plugin!=NULL)
			{
				pm->plugin->run(args);//运行
			}
			else
			{
				log->error("the plugin is not loaded corectly!");
				result=100;
			}
		}
		else
		{
			log->error("the plugin is not loaded");
			result=1;
		}
		omp_unset_lock(&pm->lock);
	}
	return result;
}

string PluginManager::name()
{
	return "pluginmanager";
}
string PluginManager::desc()
{
	return "plugin管理服务";
}
void PluginManager::run()
{
	do{
		omp_set_lock(&pllock);
		DIR *dirptr=NULL;
		struct dirent *entry;
		dirptr=opendir(Application::getInstance()->envar["PLUGIN_DIR"].c_str());
		if(dirptr!=NULL)
		{
			while(NULL!=(entry=readdir(dirptr)))
			{ 
				string fname(entry->d_name);
				if(fname.find("lib")==0&&fname.find(".so")==(fname.length()-3))
				{
					string pname(fname,fname.find("lib")+3,fname.find(".so")-fname.find("lib")-3);
					if(plugins[pname]==NULL)
					{
						plugins[pname]=new PluginMonitor();
					}
					omp_set_lock(&plugins[pname]->lock);
					plugins[pname]->loc=Application::getInstance()->envar["PLUGIN_DIR"]+"/"+fname;
					omp_unset_lock(&plugins[pname]->lock);
				}
			}
			closedir(dirptr);
		}
		omp_unset_lock(&pllock);
		sleep(5);//默认5秒钟扫描一次
	}while(Application::getInstance()->envar["PLUGINDIRLISTENING"]=="true");
}

string PluginManager::Lspl::name()
{
	return "lspl";
}
string PluginManager::LoadPlugin::name()
{
	return "loadplugin";
}
string PluginManager::RunPlugin::name()
{
	return "runplugin";
}
string PluginManager::Lspl::desc()
{
	return "可用插件列表";
}
string PluginManager::LoadPlugin::desc()
{
	return "加载插件";
}
string PluginManager::RunPlugin::desc()
{
	return "运行插件";
}
int PluginManager::Lspl::exec(vector<string>)
{
	omp_set_lock(&PluginManager::getInstance()->pllock);
	cout<<"plugin list:"<<endl;
	cout<<"name\tstatu\tthreadnum\tlocation"<<endl;
	map<string,PluginMonitor*>::const_iterator map_it=PluginManager::getInstance()->plugins.begin();
	for(;map_it!=PluginManager::getInstance()->plugins.end();map_it++)
	{
		cout<<map_it->first<<"\t"<<map_it->second->statu<<"\t"<<map_it->second->threadnum<<"\t\t"<<map_it->second->loc<<endl;
	}
	omp_unset_lock(&PluginManager::getInstance()->pllock);
	return 0;
}
int PluginManager::LoadPlugin::exec(vector<string> args)
{
	if(args.size()<2)
	{
		cout<<"need a plugin name"<<endl;
		return 1;
	}
	return PluginManager::getInstance()->loadPlugin(args[1]);
}

int PluginManager::RunPlugin::exec(vector<string> args)
{
	return PluginManager::getInstance()->runPlugin(args);
}
